#include "file.h"
#include "list.h"
#include <errno.h>

FILE * openFile(char * fileName,char * mode)
{
     FILE * pf = fopen(fileName,mode);
     if(pf == NULL)
     {
          //用来打印errno对应的错误信息,errno是后台的一个错误码
          perror("打开文件出错了，原因是：");
     }
     return pf;
}

void closeFile(FILE * pf)
{
     fclose(pf);
}


//第二个参数是数据的长度
char * readLine(FILE * pf,int len)
{
     //分配一个空间，准备用来接收从文件中读取的数据
     //+1是为了给0留出空间
     char * pBuf = malloc(len+1);
     //把pBuf指向的空间清零
     memset(pBuf,0,len+1);
     char ch;
     //第一个参数是指定要从哪个文件读取数据
     for (size_t i = 0; i < len; i++)
     {
          //从文件指针所指向的文件里面读取一个字符
          ch = fgetc(pf);
          //feof=判断pf所指向的文件中的光标是否到达了文件的末尾
          if(ch == '\n'||feof(pf))
          {
               break;
          }
          else
          {
               pBuf[i] = ch;
               // printf("%c\n",ch);
          }
     }
     //检测到还没有读取到行尾，就继续读，知道光标到达行尾
     while(len>0&&ch!='\n'&&feof(pf)==0)
     {
          ch = fgetc(pf);
     }
     
     return pBuf;
}

void writeInt(FILE * pf,int x)
{
     //把整数打印到文件中
     fprintf(pf,"%d",x);
}

int readInt(FILE * pf)
{
     int x;
     fscanf(pf,"%d",&x);
     return x;
}

void writeFloat(FILE * pf, float x)
{
     fprintf(pf,"%f",x);
}

int readFloat(FILE * pf)
{
     float x;
     fscanf(pf,"%f",&x);
     return x;
}

void writeLine(FILE * pf, char * pStr)
{
     //和printf相同，用来打印一个字符串和回车，但但因的地方不同，fprintf是把数据打印到文件中
     //第一个参数是指定要打印到哪个文件
     fprintf(pf,"%s\n",pStr);
}

void writeString(FILE * pf,char * pStr)
{
     fprintf(pf,"%s",pStr);
}

char * readString(FILE * pf,int len)
{
     //分配一个空间，准备用来接收从文件中读取的数据
     //+1是为了给0留出空间
     char * pBuf = malloc(len+1);
     //把pBuf指向的空间清零
     memset(pBuf,0,len+1);
     //读取指定数量的字符
     for (size_t i = 0; i < len; i++)
     {
          
          char ch = fgetc(pf);
          if (feof(pf))
          {
               break;
          }
          
          pBuf[i] = ch;
          
         
          
     }
     return pBuf;
}

//二进制文件操作就是把数据在内存中的样子直接搬到文件中，反之就是把存储在文件中的数据直接搬到内存中，不经过格式转换
void write(FILE * pf , void * pBuf , int size)
{
     //参数1：数据的地址
     //参数2：数据的字节数
     //参数3：有多少个参数2那么多字节数量
     //参数4：文件的指针
     if(0 == fwrite(pBuf,size,1,pf))
     {
          perror("写入数据失败，原因是：");
     }
}

int read(FILE * pf , void * pBuf , int size)
{
     //参数1：数据的地址
     //参数2：数据的字节数
     //参数3：有多少个参数2那么多字节数量
     //参数4：文件的指针
     if(0 == fread(pBuf,size,1,pf))
     {
          // perror("读取数据失败，原因是：");
          return 0 ;
     }
     return 1;
}

struct node * loadListFromFile(char * pFileName,int dataSize)
{
     //创建链表的头结点，也代表链表
     struct node * pHead = createLists(pHead);
     FILE * pf = openFile(pFileName,"rb");
     //先分配一个数据的空间
     void * p = malloc(dataSize);
     //读取一个dataSize字节数
     int ret = read(pf,p,dataSize);

     //如果返回值不为0说明读取成功了，否则说明文件已经到了末尾
     while(ret != 0)
     {
          fgetc(pf);
          //把读取的数据地址加入到链表中
          add(pHead,p);
          //重新分配一个空间
          p = malloc(dataSize);
          //继续读取下面的数据
          ret = read(pf,p,dataSize);
     }
     if(ret == 0)
     {
          free(p);
     }
     closeFile(pf);
     //把链表返回出去
     return pHead;
}

void saveListToFile(char * pFileName, struct node * pHead, int dataSize)
{
     FILE * pf = openFile(pFileName,"wb");

     //等于链表的第一个
     struct node * pTemp = pHead->pNext;
     //不为头节点，说明链表没有结束
     while (pTemp!=pHead)
     {
          //把链表节点中的数据保存到文件里
          write(pf,pTemp->pData,dataSize);
          fputc('\n',pf);            //换行
          pTemp = pTemp->pNext;
     }
     
     closeFile(pf);
}